package service

import (
	"admin-system/internal/config"
	"admin-system/internal/model"
	"encoding/json"
	"errors"
	"fmt"
	"log"
)

// MenuService 菜单服务
type MenuService struct{}

// NewMenuService 创建菜单服务实例
func NewMenuService() *MenuService {
	return &MenuService{}
}

// List 获取菜单列表
func (s *MenuService) List(page, pageSize int, keyword string) ([]model.Menu, int64, error) {
	var menus []model.Menu
	var total int64

	db := config.DB

	// 构建查询条件
	query := db.Model(&model.Menu{})
	if keyword != "" {
		query = query.Where("name LIKE ? OR path LIKE ? OR component LIKE ?",
			"%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%")
	}

	// 获取总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, fmt.Errorf("获取菜单总数失败: %v", err)
	}

	// 分页查询
	offset := (page - 1) * pageSize
	if err := query.Offset(offset).Limit(pageSize).Order("sort ASC, id ASC").Find(&menus).Error; err != nil {
		return nil, 0, fmt.Errorf("获取菜单列表失败: %v", err)
	}

	return menus, total, nil
}

// GetTree 获取菜单树
func (s *MenuService) GetTree() ([]model.MenuResponse, error) {
	var menus []model.Menu
	if err := config.DB.Order("sort ASC, id ASC").Find(&menus).Error; err != nil {
		return nil, fmt.Errorf("获取菜单列表失败: %v", err)
	}

	return s.buildMenuResponseTree(menus), nil
}

// GetByID 根据ID获取菜单
func (s *MenuService) GetByID(id uint) (*model.Menu, error) {
	var menu model.Menu
	if err := config.DB.First(&menu, id).Error; err != nil {
		return nil, fmt.Errorf("菜单不存在: %v", err)
	}
	return &menu, nil
}

// Create 创建菜单
func (s *MenuService) Create(req *model.MenuCreateRequest) (*model.Menu, error) {
	// 验证父菜单是否存在
	if req.ParentID != nil {
		if _, err := s.GetByID(*req.ParentID); err != nil {
			return nil, errors.New("父菜单不存在")
		}
	}

	// 检查菜单名是否已存在（同级别下）
	if err := s.checkMenuNameExists(req.Name, req.ParentID, 0); err != nil {
		return nil, err
	}

	// 创建菜单
	menu := model.Menu{
		ParentID:  req.ParentID,
		Name:      req.Name,
		Path:      req.Path,
		Component: req.Component,
		Redirect:  req.Redirect,
		Meta:      req.Meta,
		Sort:      req.Sort,
		Hidden:    req.Hidden,
		Status:    req.Status,
	}

	// 设置默认状态
	if menu.Status == 0 {
		menu.Status = 1
	}

	// 验证Meta字段是否为有效JSON
	if menu.Meta != "" {
		var meta interface{}
		if err := json.Unmarshal([]byte(menu.Meta), &meta); err != nil {
			return nil, errors.New("Meta字段必须是有效的JSON格式")
		}
	}

	if err := config.DB.Create(&menu).Error; err != nil {
		return nil, fmt.Errorf("创建菜单失败: %v", err)
	}

	return &menu, nil
}

// Update 更新菜单
func (s *MenuService) Update(id uint, req *model.MenuUpdateRequest) (*model.Menu, error) {
	// 检查菜单是否存在
	menu, err := s.GetByID(id)
	if err != nil {
		return nil, err
	}

	// 验证父菜单是否存在
	if req.ParentID != nil {
		if *req.ParentID == id {
			return nil, errors.New("不能将自己设置为父菜单")
		}
		if _, err := s.GetByID(*req.ParentID); err != nil {
			return nil, errors.New("父菜单不存在")
		}
		// 检查是否会形成循环引用
		if err := s.checkCircularReference(id, *req.ParentID); err != nil {
			return nil, err
		}
	}

	// 检查菜单名是否已存在（同级别下，排除自己）
	if err := s.checkMenuNameExists(req.Name, req.ParentID, id); err != nil {
		return nil, err
	}

	// 验证Meta字段是否为有效JSON
	if req.Meta != "" {
		var meta interface{}
		if err := json.Unmarshal([]byte(req.Meta), &meta); err != nil {
			return nil, errors.New("Meta字段必须是有效的JSON格式")
		}
	}

	// 更新菜单信息
	menu.ParentID = req.ParentID
	menu.Name = req.Name
	menu.Path = req.Path
	menu.Component = req.Component
	menu.Redirect = req.Redirect
	menu.Meta = req.Meta
	menu.Sort = req.Sort
	menu.Hidden = req.Hidden
	menu.Status = req.Status

	if err := config.DB.Save(menu).Error; err != nil {
		return nil, fmt.Errorf("更新菜单失败: %v", err)
	}

	return menu, nil
}

// Delete 删除菜单
func (s *MenuService) Delete(id uint) error {
	// 检查菜单是否存在
	menu, err := s.GetByID(id)
	if err != nil {
		return err
	}

	// 检查是否有子菜单
	var childCount int64
	if err := config.DB.Model(&model.Menu{}).Where("parent_id = ?", id).Count(&childCount).Error; err != nil {
		return fmt.Errorf("检查子菜单失败: %v", err)
	}

	if childCount > 0 {
		return errors.New("存在子菜单，无法删除")
	}

	// 检查菜单是否被角色使用
	var roleMenuCount int64
	if err := config.DB.Model(&model.RoleMenu{}).Where("menu_id = ?", id).Count(&roleMenuCount).Error; err != nil {
		return fmt.Errorf("检查菜单使用情况失败: %v", err)
	}

	if roleMenuCount > 0 {
		return errors.New("菜单正在被角色使用，无法删除")
	}

	// 删除菜单
	if err := config.DB.Delete(menu).Error; err != nil {
		return fmt.Errorf("删除菜单失败: %v", err)
	}

	return nil
}

// UpdateSort 批量更新菜单排序
func (s *MenuService) UpdateSort(sortData []struct {
	ID   uint `json:"id"`
	Sort int  `json:"sort"`
}) error {
	// 开始事务
	tx := config.DB.Begin()
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
		}
	}()

	for _, item := range sortData {
		if err := tx.Model(&model.Menu{}).Where("id = ?", item.ID).Update("sort", item.Sort).Error; err != nil {
			tx.Rollback()
			return fmt.Errorf("更新菜单排序失败: %v", err)
		}
	}

	tx.Commit()
	return nil
}

// GetAll 获取所有菜单（用于角色分配）
func (s *MenuService) GetAll() ([]model.Menu, error) {
	var menus []model.Menu
	if err := config.DB.Where("status = ?", 1).Order("sort ASC, id ASC").Find(&menus).Error; err != nil {
		return nil, fmt.Errorf("获取菜单列表失败: %v", err)
	}
	return menus, nil
}

// GetAllTree 获取所有菜单树（用于角色分配）
func (s *MenuService) GetAllTree() ([]model.MenuTree, error) {
	menus, err := s.GetAll()
	if err != nil {
		return nil, err
	}

	return s.buildMenuTree(menus), nil
}

// checkMenuNameExists 检查菜单名是否已存在（同级别下）
func (s *MenuService) checkMenuNameExists(name string, parentID *uint, excludeID uint) error {
	var count int64
	query := config.DB.Model(&model.Menu{}).Where("name = ?", name)

	if parentID == nil {
		query = query.Where("parent_id IS NULL")
	} else {
		query = query.Where("parent_id = ?", *parentID)
	}

	if excludeID > 0 {
		query = query.Where("id != ?", excludeID)
	}

	if err := query.Count(&count).Error; err != nil {
		return fmt.Errorf("检查菜单名失败: %v", err)
	}

	if count > 0 {
		return errors.New("同级别下菜单名已存在")
	}

	return nil
}

// checkCircularReference 检查是否会形成循环引用
func (s *MenuService) checkCircularReference(menuID, parentID uint) error {
	// 递归检查父菜单链
	currentParentID := parentID
	for currentParentID != 0 {
		if currentParentID == menuID {
			return errors.New("不能形成循环引用")
		}

		var parent model.Menu
		if err := config.DB.First(&parent, currentParentID).Error; err != nil {
			break // 父菜单不存在，跳出循环
		}

		if parent.ParentID == nil {
			break // 到达根菜单
		}

		currentParentID = *parent.ParentID
	}

	return nil
}

// buildMenuResponseTree 构建菜单响应树
func (s *MenuService) buildMenuResponseTree(menus []model.Menu) []model.MenuResponse {
	// 创建菜单映射
	menuMap := make(map[uint]*model.MenuResponse)
	var rootMenus []model.MenuResponse

	// 第一遍：创建所有菜单节点
	for _, menu := range menus {
		// 解析Meta JSON
		var meta interface{}
		if menu.Meta != "" {
			json.Unmarshal([]byte(menu.Meta), &meta)
		}

		menuResponse := &model.MenuResponse{
			ID:        menu.ID,
			ParentID:  menu.ParentID,
			Name:      menu.Name,
			Path:      menu.Path,
			Component: menu.Component,
			Redirect:  menu.Redirect,
			Meta:      meta,
			Sort:      menu.Sort,
			Hidden:    menu.Hidden,
			Status:    menu.Status,
			CreatedAt: menu.CreatedAt,
			UpdatedAt: menu.UpdatedAt,
			Children:  []model.MenuResponse{},
		}
		menuMap[menu.ID] = menuResponse
	}

	// 第二遍：构建树形结构
	var rootMenuIDs []uint
	for _, menu := range menus {
		menuResponse := menuMap[menu.ID]
		if menu.ParentID == nil {
			// 根菜单
			rootMenuIDs = append(rootMenuIDs, menu.ID)
		} else {
			// 子菜单
			if parent, exists := menuMap[*menu.ParentID]; exists {
				parent.Children = append(parent.Children, *menuResponse)
			}
		}
	}

	// 收集根菜单（在所有子菜单都添加完成后）
	for _, rootID := range rootMenuIDs {
		if rootMenu, exists := menuMap[rootID]; exists {
			rootMenus = append(rootMenus, *rootMenu)
		}
	}

	return rootMenus
}

// buildMenuTree 构建菜单树（用于角色分配）
func (s *MenuService) buildMenuTree(menus []model.Menu) []model.MenuTree {
	log.Printf("构建菜单树，输入菜单数量: %d", len(menus))

	// 创建菜单映射
	menuMap := make(map[uint]*model.MenuTree)
	var rootMenus []model.MenuTree

	// 第一遍：创建所有菜单节点
	for _, menu := range menus {
		log.Printf("处理菜单: ID=%d, Name=%s, ParentID=%v", menu.ID, menu.Name, menu.ParentID)

		// 解析Meta JSON
		var meta interface{}
		if menu.Meta != "" {
			json.Unmarshal([]byte(menu.Meta), &meta)
		}

		menuTree := &model.MenuTree{
			ID:        menu.ID,
			ParentID:  menu.ParentID,
			Name:      menu.Name,
			Path:      menu.Path,
			Component: menu.Component,
			Redirect:  menu.Redirect,
			Meta:      meta,
			Sort:      menu.Sort,
			Hidden:    menu.Hidden,
			Children:  []model.MenuTree{},
		}
		menuMap[menu.ID] = menuTree
	}

	// 第二遍：构建树形结构
	var rootMenuIDs []uint
	for _, menu := range menus {
		menuTree := menuMap[menu.ID]
		if menu.ParentID == nil {
			// 根菜单
			log.Printf("找到根菜单: ID=%d, Name=%s", menu.ID, menu.Name)
			rootMenuIDs = append(rootMenuIDs, menu.ID)
		} else {
			// 子菜单
			log.Printf("处理子菜单: ID=%d, Name=%s, ParentID=%d", menu.ID, menu.Name, *menu.ParentID)
			if parent, exists := menuMap[*menu.ParentID]; exists {
				log.Printf("将子菜单 %s 添加到父菜单 %s", menu.Name, parent.Name)
				parent.Children = append(parent.Children, *menuTree)
			} else {
				log.Printf("警告：找不到父菜单 ID=%d", *menu.ParentID)
			}
		}
	}

	// 收集根菜单（在所有子菜单都添加完成后）
	log.Printf("收集根菜单，根菜单数量: %d", len(rootMenuIDs))
	for _, rootID := range rootMenuIDs {
		if rootMenu, exists := menuMap[rootID]; exists {
			log.Printf("添加根菜单: ID=%d, Name=%s, 子菜单数量=%d", rootMenu.ID, rootMenu.Name, len(rootMenu.Children))
			rootMenus = append(rootMenus, *rootMenu)
		}
	}

	log.Printf("最终返回菜单数量: %d", len(rootMenus))
	return rootMenus
}
